home *** CD-ROM | disk | FTP | other *** search
/ Mac Format 1994 October / Macformat17.cdr / Shareware City / Developers / shutdown-fx-201-c / sfx ƒ / sfx control app ƒ / Shell ƒ / help.c < prev    next >
Text File  |  1994-07-11  |  13KB  |  532 lines

  1. /**********************************************************************\
  2.  
  3. File:        help.c
  4.  
  5. Purpose:    This module handles displaying the different help windows.
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program in a file named "GNU General Public License".
  19. If not, write to the Free Software Foundation, 675 Mass Ave,
  20. Cambridge, MA 02139, USA.
  21.  
  22. \**********************************************************************/
  23.  
  24. #include "help.h"
  25. #include "environment.h"
  26. #include "util.h"
  27. #include "buttons.h"
  28. #include "timing.h"
  29. #include "program globals.h"
  30.  
  31. #define DEAD_SPACE_TOP        10
  32. #define DEAD_SPACE_LEFT        10
  33. #define DEAD_SPACE_BOTTOM    27
  34. #define DEAD_SPACE_RIGHT    10
  35. #define    TEXT_RECT_WIDTH        405
  36. #define    TEXT_RECT_HEIGHT    250
  37. #define    BUTTON_WIDTH        62
  38. #define    BUTTON_HEIGHT        17
  39. #define BUTTON_GAP            1
  40. #define    XREF_DEAD_SPACE_TOP    5
  41. #define XREF_TEXT_WIDTH        46
  42. #define    XREF_WIDTH            70
  43. #define    XREF_HEIGHT            17
  44. #define    XREF_GAP            5
  45.  
  46. #define MAX_MAIN_TOPICS        20
  47.  
  48. #define    MAX_XREFS            4
  49.  
  50. #define MAIN_TOPIC_ID        600
  51.  
  52. #define theWindowWidth (boundsRect.right-boundsRect.left)
  53. #define theWindowHeight (boundsRect.bottom-boundsRect.top)
  54. #define CorrectTime 1
  55.  
  56. typedef unsigned char    **CharHandle;
  57.  
  58. typedef struct
  59. {
  60.     long            offset;
  61.     short            lineHeight;
  62.     short            fontDescent;
  63.     short            fontNum;
  64.     unsigned char    fontStyle;
  65.     unsigned char    unused1;
  66.     short            fontSize;
  67.     short            unused2;
  68.     short            unused3;
  69.     short            unused4;
  70. } OneStyle;
  71.  
  72. typedef struct
  73. {
  74.     short        numStyles;
  75.     OneStyle    theStyle[31];
  76. } StylRec, *StylPtr, **StylHandle;
  77.  
  78. enum
  79. {
  80.     kLeft=0,
  81.     kCenter
  82. };
  83.  
  84. short            gNumMainTopics;
  85. short            gNumXRefs[MAX_MAIN_TOPICS];
  86.  
  87. Str31            gMainTopicTitle[MAX_MAIN_TOPICS];
  88. Rect            gMainTopicRect[MAX_MAIN_TOPICS];
  89. short            gMainTopicID[MAX_MAIN_TOPICS];
  90.  
  91. short            gXRefIndex[MAX_MAIN_TOPICS][MAX_XREFS];
  92. Rect            gXRefRect[MAX_XREFS];
  93.  
  94. short            gMainTopicShowing;        /* saved in prefs file */
  95.  
  96. Rect            gTextRect;
  97. CharHandle        gTheText;
  98. StylHandle        gTheStyle;
  99.  
  100. /*-----------------------------------------------------------------------------------*/
  101. /* internal stuff for help.c                                                         */
  102.  
  103. static void SetupTheHelpWindow(WindowDataHandle theData);
  104. static void ShutdownTheHelpWindow(WindowDataHandle theData);
  105. static void InitializeTheHelpWindow(WindowDataHandle theData);
  106. static void OpenTheHelpWindow(WindowDataHandle theData);
  107. static void KeyPressedInHelpWindow(WindowDataHandle theData, unsigned char keyPressed);
  108. static void MouseClickedInHelpWindow(WindowDataHandle theData, Point mouseLoc);
  109. static void DrawTheHelpWindow(short theDepth);
  110. static void DrawTheText(CharHandle theText, StylHandle theStyleHandle, short theJust,
  111.     short theMode, Rect theRect);
  112. static void DrawTheShadowBox(Rect theRect);
  113. static short ParseRawTitle(Str255 theTitle, short *xRef, short *numXRefs);
  114. static void GoToPage(WindowDataHandle theData, short mainTopic, Boolean updateNow);
  115. static void GetTextResources(short mainTopic);
  116. static void DisposeTextResources(void);
  117. static void CalculateXRefInfo(short index, short *mainTopic, Str255 name);
  118.  
  119.  
  120. short HelpWindowDispatch(WindowDataHandle theData, short theMessage, unsigned long misc)
  121. {
  122.     unsigned char    theChar;
  123.     Point            thePoint;
  124.     short            theDepth;
  125.     
  126.     switch (theMessage)
  127.     {
  128.         case kUpdate:
  129.             theDepth=misc&0x7fff;
  130.             DrawTheHelpWindow(theDepth);
  131.             return kSuccess;
  132.             break;
  133.         case kKeydown:
  134.             theChar=misc&charCodeMask;
  135.             KeyPressedInHelpWindow(theData, theChar);
  136.             return kSuccess;
  137.             break;
  138.         case kMousedown:
  139.             thePoint.h=(misc>>16)&0x7fff;
  140.             thePoint.v=misc&0x7fff;
  141.             MouseClickedInHelpWindow(theData, thePoint);
  142.             return kSuccess;
  143.             break;
  144.         case kOpen:
  145.             OpenTheHelpWindow(theData);
  146.             return kSuccess;
  147.             break;
  148.         case kInitialize:
  149.             InitializeTheHelpWindow(theData);
  150.             return kSuccess;
  151.             break;
  152.         case kStartup:
  153.             SetupTheHelpWindow(theData);
  154.             return kSuccess;
  155.             break;
  156.         case kShutdown:
  157.             ShutdownTheHelpWindow(theData);
  158.             return kSuccess;
  159.             break;
  160.     }
  161.     
  162.     return kFailure;        /* revert to default processing for all other messages */
  163. }
  164.  
  165. void SetupTheHelpWindow(WindowDataHandle theData)
  166. {
  167.     short            i,j;
  168.     unsigned char    *helpStr="\pHelp";
  169.     Handle            temp;
  170.     short            textID;
  171.     short            centeringOffset;
  172.     
  173.     temp=GetResource('STR#', MAIN_TOPIC_ID);
  174.     gNumMainTopics=**((short**)temp);
  175.     ReleaseResource(temp);
  176.     centeringOffset=DEAD_SPACE_TOP;
  177.     for (i=0; i<gNumMainTopics; i++)
  178.     {
  179.         GetIndString(gMainTopicTitle[i], MAIN_TOPIC_ID, i+1);
  180.         gMainTopicID[i]=ParseRawTitle(gMainTopicTitle[i], gXRefIndex[i], &(gNumXRefs[i]));
  181.         SetRect(&gMainTopicRect[i], DEAD_SPACE_LEFT, centeringOffset+(BUTTON_HEIGHT+BUTTON_GAP)*i,
  182.             DEAD_SPACE_LEFT+BUTTON_WIDTH, centeringOffset+(BUTTON_HEIGHT+BUTTON_GAP)*(i+1));
  183.     }
  184.     
  185.     for (i=0; i<MAX_XREFS; i++)
  186.     {
  187.         SetRect(&gXRefRect[i], XREF_TEXT_WIDTH+DEAD_SPACE_LEFT+BUTTON_WIDTH+DEAD_SPACE_LEFT+
  188.             i*(XREF_WIDTH+XREF_GAP), DEAD_SPACE_TOP+TEXT_RECT_HEIGHT+XREF_DEAD_SPACE_TOP,
  189.             XREF_TEXT_WIDTH+DEAD_SPACE_LEFT+BUTTON_WIDTH+DEAD_SPACE_LEFT+
  190.             i*(XREF_WIDTH+XREF_GAP)+XREF_WIDTH, DEAD_SPACE_TOP+TEXT_RECT_HEIGHT+
  191.             XREF_DEAD_SPACE_TOP+XREF_HEIGHT);
  192.     }
  193.     
  194.     gTheText=gTheStyle=0L;
  195.     GoToPage(0L, gMainTopicShowing, FALSE);
  196.     
  197.     SetRect(&gTextRect, DEAD_SPACE_LEFT+BUTTON_WIDTH+DEAD_SPACE_LEFT, DEAD_SPACE_TOP,
  198.         DEAD_SPACE_LEFT+BUTTON_WIDTH+DEAD_SPACE_LEFT+TEXT_RECT_WIDTH,
  199.         DEAD_SPACE_TOP+TEXT_RECT_HEIGHT);
  200.     
  201.     (**theData).maxDepth=8;
  202.     (**theData).windowWidth=DEAD_SPACE_LEFT+BUTTON_WIDTH+DEAD_SPACE_LEFT+
  203.         TEXT_RECT_WIDTH+DEAD_SPACE_RIGHT;
  204.     (**theData).windowHeight=DEAD_SPACE_TOP+TEXT_RECT_HEIGHT+DEAD_SPACE_BOTTOM;
  205.     (**theData).windowType=noGrowDocProc;    /* document-looking thing */
  206.     (**theData).hasCloseBox=TRUE;
  207.     (**theData).windowBounds.top=50;
  208.     (**theData).windowBounds.left=6;
  209.     SetIndWindowTitle(kHelp, helpStr);
  210. }
  211.  
  212. void ShutdownTheHelpWindow(WindowDataHandle theData)
  213. {
  214.     DisposeTextResources();
  215. }
  216.  
  217. void InitializeTheHelpWindow(WindowDataHandle theData)
  218. {
  219.     (**theData).initialTopLeft.v=(**theData).windowBounds.top-9;
  220.     (**theData).initialTopLeft.h=(**theData).windowBounds.left;
  221. }
  222.  
  223. void OpenTheHelpWindow(WindowDataHandle theData)
  224. {
  225.     (**theData).offscreenNeedsUpdate=TRUE;
  226. }
  227.  
  228. void KeyPressedInHelpWindow(WindowDataHandle theData, unsigned char keyPressed)
  229. {
  230.     short            oldTopic;
  231.     
  232.     ObscureCursor();
  233.     
  234.     switch (keyPressed)
  235.     {
  236.         case 0x1c:                                        /* left arrow */
  237.             gMainTopicShowing--;
  238.             if (gMainTopicShowing<0)
  239.                 gMainTopicShowing=gNumMainTopics-1;
  240.             GoToPage(theData, gMainTopicShowing, TRUE);
  241.             break;
  242.         case 0x1d:                                        /* right arrow */
  243.             gMainTopicShowing++;
  244.             if (gMainTopicShowing>=gNumMainTopics)
  245.                 gMainTopicShowing=0;
  246.             GoToPage(theData, gMainTopicShowing, TRUE);
  247.             break;
  248.         case 0x1b:                                        /* escape key */
  249.             CloseTheWindow(theData);
  250.             break;
  251.     }
  252. }
  253.  
  254. void MouseClickedInHelpWindow(WindowDataHandle theData, Point mouseLoc)
  255. {
  256.     short            theDepth;
  257.     short            i;
  258.     Str255            name;
  259.     short            newMain;
  260.     
  261.     theDepth=(**theData).windowDepth;
  262.     
  263.     for (i=0; i<gNumXRefs[gMainTopicShowing]; i++)
  264.     {
  265.         if (PtInRect(mouseLoc, &gXRefRect[i]))
  266.         {
  267.             CalculateXRefInfo(gXRefIndex[gMainTopicShowing][i], &newMain, name);
  268.             
  269.             if (newMain!=-1)
  270.             {
  271.                 if (Track3DButton(&gXRefRect[i], name, 0L, theDepth))
  272.                 {
  273.                     GoToPage(theData, newMain, TRUE);
  274.                     return;
  275.                 }
  276.             }
  277.         }
  278.     }
  279.     
  280.     for (i=0; i<gNumMainTopics; i++)
  281.     {
  282.         if (PtInRect(mouseLoc, &gMainTopicRect[i]))
  283.         {
  284.             if (Track3DButton(&gMainTopicRect[i], gMainTopicTitle[i], 0L, theDepth))
  285.             {
  286.                 GoToPage(theData, i, TRUE);
  287.                 return;
  288.             }
  289.         }
  290.     }
  291. }
  292.  
  293. void DrawTheHelpWindow(short theDepth)
  294. {
  295.     GrafPtr            curPort;
  296.     short            i,j;
  297.     Boolean            isColor;
  298.     Rect            tempRect;
  299.     Str255            theStr;
  300.     short            dummy1, dummy2;
  301.     
  302.     isColor=(theDepth>2);
  303.     
  304.     GetPort(&curPort);
  305.     EraseRect(&(curPort->portRect));
  306.     
  307.     DrawTheShadowBox(gTextRect);
  308.     if (gTheText!=0L)
  309.     {
  310.         tempRect=gTextRect;
  311.         InsetRect(&tempRect, 8, 4);
  312.         DrawTheText(gTheText, gTheStyle, kLeft, srcOr, tempRect);
  313.     }
  314.     
  315.     for (i=0; i<gNumMainTopics; i++)
  316.     {
  317.         Draw3DButton(&gMainTopicRect[i], gMainTopicTitle[i], 0L, theDepth, FALSE);
  318.     }
  319.     
  320.     for (i=0; i<gNumXRefs[gMainTopicShowing]; i++)
  321.     {
  322.         CalculateXRefInfo(gXRefIndex[gMainTopicShowing][i], &dummy1, theStr);
  323.         Draw3DButton(&gXRefRect[i], theStr, 0L, theDepth, FALSE);
  324.     }
  325.     
  326.     if (gNumXRefs[gMainTopicShowing]>0)
  327.     {
  328.         MoveTo(gXRefRect[0].left-XREF_TEXT_WIDTH, gXRefRect[0].bottom-5);
  329.         TextFont(geneva);
  330.         TextSize(9);
  331.         DrawString("\pSee also:");
  332.     }
  333. }
  334.  
  335. void DrawTheText(CharHandle theText, StylHandle theStyleHandle, short theJust,
  336.     short theMode, Rect theRect)
  337. {
  338.     short            i, numStyles;
  339.     long            textPos;
  340.     long            maxOffset;
  341.     Str255            thisLine;
  342.     Boolean            notDoneYet;
  343.     unsigned char    thisChar;
  344.     short            theRow, theCol;
  345.     unsigned char    lastEnd, thisEnd;
  346.     Boolean            overRun;
  347.     
  348.     numStyles=(**theStyleHandle).numStyles;
  349.     textPos=0L;
  350.     theRow=theRect.top+(**theStyleHandle).theStyle[0].fontDescent+1;
  351.     theCol=theRect.left;
  352.     thisLine[0]=0x00;
  353.     lastEnd=0;
  354.     for (i=0; i<numStyles; i++)
  355.     {
  356.         if (i==numStyles-1)
  357.             maxOffset=GetHandleSize(theText);
  358.         else
  359.             maxOffset=(**theStyleHandle).theStyle[i+1].offset;
  360.         
  361.         TextFont((**theStyleHandle).theStyle[i].fontNum);
  362.         TextFace((**theStyleHandle).theStyle[i].fontStyle);
  363.         TextSize((**theStyleHandle).theStyle[i].fontSize);
  364.         TextMode(theMode);
  365.         
  366.         while (textPos<maxOffset)
  367.         {
  368.             notDoneYet=TRUE;
  369.             while ((textPos<maxOffset) && (notDoneYet))
  370.             {
  371.                 thisChar=thisLine[++thisLine[0]]=(*theText)[textPos++];
  372.                 notDoneYet=((thisChar!=' ') && (thisChar!=0x0d));
  373.             }
  374.             
  375.             thisEnd=thisLine[0];
  376.             overRun=(theRect.right-theCol<=StringWidth(thisLine));
  377.             
  378.             if ((overRun) || (thisChar==0x0d) || (textPos==maxOffset))
  379.             {
  380.                 if (overRun)
  381.                     thisLine[0]=lastEnd;
  382.                 if (theJust==kCenter)
  383.                     MoveTo((theRect.right-theRect.left-StringWidth(thisLine))/2+
  384.                             theCol, theRow);
  385.                 else
  386.                     MoveTo(theCol, theRow);
  387.                 theCol+=StringWidth(thisLine);
  388.                 DrawString(thisLine);
  389.                 if (overRun)
  390.                 {
  391.                     BlockMove(&thisLine[lastEnd+1], &thisLine[1], thisEnd-lastEnd+1);
  392.                     if (thisEnd>=lastEnd)
  393.                     {
  394.                         thisLine[0]=thisEnd-lastEnd-1;
  395.                         textPos--;
  396.                     }
  397.                     else
  398.                         thisEnd=thisLine[0]=0x00;
  399.                 }
  400.                 else thisLine[0]=0x00;
  401.                 if ((overRun) || (thisChar==0x0d))
  402.                 {
  403.                     theRow+=(**theStyleHandle).theStyle[i].lineHeight;
  404.                     theCol=theRect.left;
  405.                 }
  406.             }
  407.             
  408.             lastEnd=thisEnd;
  409.         }
  410.         
  411.         if (thisLine[0]!=0x00)
  412.         {
  413.             if (theJust==kCenter)
  414.                 MoveTo((theRect.right-theRect.left-StringWidth(thisLine))/2+
  415.                         theCol, theRow);
  416.             else
  417.                 MoveTo(theCol, theRow);
  418.             theCol+=StringWidth(thisLine);
  419.             DrawString(thisLine);
  420.             thisLine[0]=0x00;
  421.         }
  422.     }
  423.     TextMode(srcOr);
  424. }
  425.  
  426. void DrawTheShadowBox(Rect theRect)
  427. {
  428.     theRect.right-=2;
  429.     theRect.bottom-=2;
  430.     FrameRect(&theRect);
  431.     MoveTo(theRect.left+3, theRect.bottom+1);
  432.     Line(theRect.right-theRect.left-2, 0);
  433.     Line(0, -theRect.bottom+theRect.top+3);
  434.     MoveTo(theRect.left+3, theRect.bottom);
  435.     Line(theRect.right-theRect.left-3, 0);
  436.     Line(0, -theRect.bottom+theRect.top+4);
  437. }
  438.  
  439. short ParseRawTitle(Str255 theTitle, short *xRef, short *numXRefs)
  440. {
  441.     Str255            numStr;
  442.     unsigned long    result;
  443.     short            i,j;
  444.     Boolean            gotbullet;
  445.     Boolean            moreXRefs;
  446.     
  447.     if (xRef!=0L)
  448.     {
  449.         *numXRefs=0;
  450.         for (j=1, gotbullet=FALSE; ((j<=theTitle[0]) && (!gotbullet)); j++)
  451.             gotbullet=(theTitle[j]=='%');
  452.         if (gotbullet)
  453.         {
  454.             i=j;
  455.             do
  456.             {
  457.                 numStr[0]=0x00;
  458.                 while ((numStr[0]<=theTitle[0]-i) &&
  459.                     (((numStr[numStr[0]]=theTitle[i+(numStr[0]++)]))!=' ')) {}
  460.                 if (numStr[numStr[0]]==' ')
  461.                 {
  462.                     moreXRefs=TRUE;
  463.                     i+=numStr[0];
  464.                     numStr[0]--;
  465.                 }
  466.                 else moreXRefs=FALSE;
  467.                 StringToNum(numStr, &result);
  468.                 xRef[(*numXRefs)++]=result;
  469.             }
  470.             while (moreXRefs);
  471.             theTitle[0]=j-2;
  472.         }
  473.     }
  474.     numStr[0]=0x00;
  475.     while ((numStr[numStr[0]]=theTitle[++numStr[0]])!=' ') {}
  476.     theTitle[0]-=numStr[0];
  477.     Mymemcpy(&theTitle[1], &theTitle[numStr[0]+1], theTitle[0]);
  478.     numStr[0]--;
  479.     StringToNum(numStr, &result);
  480.     return result;
  481. }
  482.  
  483. void GoToPage(WindowDataHandle theData, short mainTopic, Boolean updateNow)
  484. {
  485.     DisposeTextResources();
  486.     GetTextResources(mainTopic);
  487.     gMainTopicShowing=mainTopic;
  488.     if (updateNow)
  489.     {
  490.         (**theData).offscreenNeedsUpdate=TRUE;
  491.         UpdateTheWindow(theData);
  492.     }
  493. }
  494.  
  495. void GetTextResources(short mainTopic)
  496. {
  497.     short            resID;
  498.     
  499.     DisposeTextResources();
  500.     resID=gMainTopicID[mainTopic];
  501.     gTheText=GetResource('TEXT', resID);
  502.     gTheStyle=GetResource('styl', resID);
  503. }
  504.  
  505. void DisposeTextResources(void)
  506. {
  507.     if (gTheText!=0L)
  508.         ReleaseResource(gTheText);
  509.     if (gTheStyle!=0L)
  510.         ReleaseResource(gTheStyle);
  511.     gTheText=gTheStyle=0L;
  512. }
  513.  
  514. void CalculateXRefInfo(short index, short *mainTopic, Str255 name)
  515. {
  516.     short            theMain;
  517.     unsigned char    *bad="\pBad XRef!";
  518.     
  519.     for (theMain=0; theMain<gNumMainTopics; theMain++)
  520.     {
  521.         if (index==gMainTopicID[theMain])
  522.         {
  523.             Mymemcpy(name, gMainTopicTitle[theMain], gMainTopicTitle[theMain][0]+1);
  524.             *mainTopic=theMain;
  525.             return;
  526.         }
  527.     }
  528.     
  529.     Mymemcpy(name, bad, bad[0]+1);
  530.     *mainTopic=-1;
  531. }
  532.